Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ASTTransformer.visit_For and fix a bug on grouped ndrange loops #648

Merged
merged 18 commits into from
Mar 25, 2020

Conversation

xumingkuan
Copy link
Contributor

@xumingkuan xumingkuan commented Mar 23, 2020

Related issue id = #631

Also make mgpcg_advanced.py able to run with self.dim = 2.

[Click here for the format server]

@xumingkuan
Copy link
Contributor Author

It gives me TypeError: list indices must be integers or slices, not Expr whenever I write sth like __ndrange.acc_dimensions[__grouped_I + 1]. I think it's necessary to have a variable in some indices in the template string in transformer.py. How can I walk around it?

loop_body = t_loop.body
inner_loop_body = loop_body[1].body
inner_loop_body[1].body[0].value = self.parse_expr(
'__I // __ndrange.acc_dimensions[__grouped_I + 1]')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using self.parse_expr to avoid the Expr index in the template string but it didn't work.

loop_body += node.body

node = ast.copy_location(t, node)
return self.visit(node) # further translate as a range for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here self.visit will further translate __grouped_I_tmp = 0 into __grouped_I_tmp = ti.expr_init(0) and you get an expr. The solution is to first visit the node body, and then do your own transform so that what you write is what you end up with.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After visiting the node body (translating as a range for), how can I locate the statements I want to modify?

Copy link
Member

@yuanming-hu yuanming-hu Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An easier way: see the trick here and protect your statements with ti.static(1) so that it won't get further translated

if ti.static(1):

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, to be clear: try __grouped_I_tmp = ti.static(0) so that this statement won't get transformed into __grouped_I_tmp = ti.expr_init(0).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After visiting the node body (translating as a range for), how can I locate the statements I want to modify?

In my understanding, the only transform you have to do here is to prepend some statements to the loop body so that you can get something like I. You don't need to modify any existing statements in the old loop body.

@yuanming-hu
Copy link
Member

An easy way to debug this is to enable print_processed=True in ti.init or @all_archs_with, so that you can look at the transformed AST and figure out why you get TypeError: list indices must be integers or slices, not Expr :-)

@xumingkuan
Copy link
Contributor Author

I need __ndrange.acc_dimensions[__grouped_I + 1] and __ndrange.bounds[__grouped_I][0].

However, __ndrange.acc_dimensions is a list, while __grouped_I + 1 is an Expr.

As the error says, list indices are not allowed to be Expr.

Maybe I should make use of GroupedNDRange to obtain a Vector but I don't know how to use it. Shall we have a Skype chat now?

@yuanming-hu
Copy link
Member

Shall we have a Skype chat now?

Sure.

@xumingkuan
Copy link
Contributor Author

After preprocessing:
def test():
  if ti.static(1):
    __ndrange = ti.expr_init(ti.ndrange((x0, y0), (x1, y1)))
    I = ti.expr_init(ti.Vector([0] * len(__ndrange.dimensions)))
    if 1:
      __ndrange_I = ti.Expr(ti.core.make_id_expr(''))
      ___begin = ti.Expr(0)
      ___end = ti.Expr(ti.subscript(__ndrange.acc_dimensions, 0))
      ___begin = ti.cast(___begin, ti.i32)
      ___end = ti.cast(___end, ti.i32)
      ti.core.begin_frontend_range_for(__ndrange_I.ptr, ___begin.ptr,
          ___end.ptr)
      __I = ti.expr_init(__ndrange_I)
      if 1:
        __grouped_I = ti.Expr(ti.core.make_id_expr(''))
        ___begin = ti.Expr(0)
        ___end = ti.Expr(len(__ndrange.dimensions))
        ___begin = ti.cast(___begin, ti.i32)
        ___end = ti.cast(___end, ti.i32)
        ti.core.begin_frontend_range_for(__grouped_I.ptr, ___begin.ptr,
            ___end.ptr)
        __grouped_I_tmp = ti.static(0)
        if 1:
          __cond = ti.chain_compare([__grouped_I + 1, len(__ndrange.
              dimensions)], ['Lt'])
          ti.core.begin_frontend_if(ti.Expr(__cond).ptr)
          ti.core.begin_frontend_if_true()
          __grouped_I_tmp = ti.expr_init(233)
          del __grouped_I_tmp
          ti.core.pop_scope()
          ti.core.begin_frontend_if_false()
          __grouped_I_tmp = ti.expr_init(__I)
          del __grouped_I_tmp
          ti.core.pop_scope()
        __tmp = ti.expr_init(233)
        if 1:
          __cond = ti.chain_compare([__grouped_I + 1, len(__ndrange.
              dimensions)], ['Lt'])
          ti.core.begin_frontend_if(ti.Expr(__cond).ptr)
          ti.core.begin_frontend_if_true()
          __I.assign(233)
          ti.core.pop_scope()
          ti.core.begin_frontend_if_false()
          ti.core.pop_scope()
        del __tmp
        ti.core.end_frontend_range_for()
        del __grouped_I
      ti.subscript(val, I).assign(ti.subscript(I, 0) + ti.subscript(I, 1) * 2)
      del __I
      ti.core.end_frontend_range_for()
      del __ndrange_I
    del I
    del __ndrange

@xumingkuan
Copy link
Contributor Author

After preprocessing:
def test():
  if ti.static(1):
    __ndrange = ti.ndrange((x0, y0), (x1, y1))
    I = ti.expr_init(ti.Vector([0] * len(__ndrange.dimensions)))
    ___begin = ti.Expr(0)
    ___end = __ndrange.acc_dimensions[0]
    ___begin = ti.cast(___begin, ti.i32)
    ___end = ti.cast(___end, ti.i32)
    __ndrange_I = ti.Expr(0)
    ti.core.begin_frontend_range_for(__ndrange_I.ptr, ___begin.ptr, ___end.ptr)
    __I = __ndrange_I
    for __grouped_I in range(len(__ndrange.dimensions)):
      __grouped_I_tmp = 0
      if __grouped_I + 1 < len(__ndrange.dimensions):
        __grouped_I_tmp = __I // __ndrange.acc_dimensions[__grouped_I + 1]
      else:
        __grouped_I_tmp = __I
      ti.subscript(I, __grouped_I).assign(__grouped_I_tmp + __ndrange.
          bounds[__grouped_I][0])
      if __grouped_I + 1 < len(__ndrange.dimensions):
        __I = __I - __grouped_I_tmp * __ndrange.acc_dimensions[__grouped_I + 1]
    ti.subscript(val, I).assign(ti.subscript(I, 0) + ti.subscript(I, 1) * 2)
    ti.core.end_frontend_range_for()

@xumingkuan xumingkuan marked this pull request as ready for review March 24, 2020 18:58
@xumingkuan xumingkuan changed the title Refactor ASTTransformer.visit_For Refactor ASTTransformer.visit_For and fix a bug on grouped ndrange loops Mar 24, 2020
@xumingkuan
Copy link
Contributor Author

Ready for review.

Copy link
Member

@yuanming-hu yuanming-hu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! Now visit_For is much easier to read. Note that currently visit_For is still a huge function. It would be good to move its components outside. For example, get_decorator and visit_static_for should be (static) member functions, at the same level of visit_For itself.

This means you might have to pass a few originally automatically captured variables (e.g. node) as member function parameters, but doing so will further clarify this function. Thanks!

examples/mgpcg_advanced.py Outdated Show resolved Hide resolved
@xumingkuan xumingkuan requested a review from yuanming-hu March 24, 2020 21:22
Copy link
Member

@yuanming-hu yuanming-hu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! This is really well done. I like your TaichiSyntaxError treatments.

I'll merge once CI passes. Let me know when you are ready to chat about the next task.

@yuanming-hu yuanming-hu merged commit 76ff830 into taichi-dev:master Mar 25, 2020
@xumingkuan xumingkuan deleted the for branch March 26, 2020 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants